library ieee;
use ieee.std_logic_1164.all;

entity cemisidfft_chip is
    port (
        CLK_i   : in std_logic;
        RESET_i : in std_logic);
end cemisidfft_chip;

architecture structural of cemisidfft_chip is
    component alu
        port (
            A_i         : in  std_logic_vector(3 downto 0);
            B_i         : in  std_logic_vector(3 downto 0);
            C_i         : in  std_logic;                   
            ALU_OP_i    : in  std_logic_vector(3 downto 0);
            ALU_o       : out std_logic_vector(3 downto 0);
            C_o         : out std_logic;
            N_o         : out std_logic;
            OVF_o       : out std_logic;
            Z_o         : out std_logic;
            CLK         : in  std_logic);
    end component;

    component hazards_unit
        port(
            CURR_INST_i : in std_logic_vector(11 downto 0);
            NEXT_INST_i : in std_logic_vector(11 downto 0);
            HAZARD_o	: out std_logic);
    end component;

    component control_unit
        port (
            VA_i          : in  std_logic_vector(1 downto 0);
            VB_i          : in  std_logic_vector(1 downto 0);
            VD_i          : in  std_logic_vector(1 downto 0);
            CONST2_i      : in  std_logic_vector(1 downto 0);
            OPCODE_i      : in  std_logic_vector(3 downto 0);
            HAZARD_i      : in  std_logic;
            CLK_i         : in  std_logic;
            RESET_i       : in  std_logic;
            IDXI_o        : out std_logic_vector(3 downto 0);
            IDXJ_o        : out std_logic_vector(3 downto 0);
            IDXK_o        : out std_logic_vector(3 downto 0);
            ALU_OP_o      : out std_logic_vector(3 downto 0);
            CONST6_o      : out std_logic_vector(5 downto 0);
            CONST_MUX_o   : out std_logic;
            INSTR_FETCH_o : out std_logic;
            WE_o          : out std_logic);
    end component;

    component inst_memory
        port(	
            RESET_i   : in std_logic;
            ADDRESS_i : in std_logic_vector(5 downto 0);
            DATA_o    : out std_logic_vector(11 downto 0));
    end component;

    component pipeline_cu_alu
        port(
            INPUT_i       : in  std_logic_vector(3 downto 0);
            CLK_i         : in  std_logic;
            OUTPUT_REG0_o : out std_logic_vector(3 downto 0);
            OUTPUT_o      : out std_logic_vector(3 downto 0));
    end component;

    component pipeline_instruction
        port(
            INPUT_i       : in  std_logic_vector(11 downto 0);
            CLK_i         : in  std_logic;
            INSTR_FETCH_i : in  std_logic;
            OUTPUT_REG0_o : out std_logic_vector(11 downto 0);
            OUTPUT_o      : out std_logic_vector(11 downto 0));
    end component;

    component pipeline_cu_vrf
        port (
            INPUT_i     : in  std_logic_vector(4 downto 0);
            CLK_i       : in  std_logic;
            OUTPUT_o    : out std_logic_vector(4 downto 0));
    end component;

    component reg4bits
        port (
            D_i   : in  std_logic_vector(3 downto 0);
            CLK_i : in  std_logic;
            Q_o   : out std_logic_vector(3 downto 0));
    end component;

    component vector_register_file
        port(
            CLK_i          : in  std_logic;
            WRITE_ENABLE_i : in  std_logic;
            DATA_i         : in  std_logic_vector  (3 downto 0);
            RA_i           : in  std_logic_vector  (1 downto 0);
            RB_i           : in  std_logic_vector  (1 downto 0);
            RD_i           : in  std_logic_vector  (1 downto 0);
            CA_i           : in  std_logic_vector  (1 downto 0);
            CB_i           : in  std_logic_vector  (1 downto 0);
            CD_i           : in  std_logic_vector  (1 downto 0);
            READ_DATA1_o   : out std_logic_vector  (3 downto 0);
            READ_DATA2_o   : out std_logic_vector  (3 downto 0));
    end component;

    signal pc_wire : std_logic_vector(5 downto 0);

    signal mem_instr_wire    : std_logic_vector(11 downto 0);
    signal curr_instr_wire   : std_logic_vector(11 downto 0);
    signal next_instr_wire   : std_logic_vector(11 downto 0);

    signal instr_const2_wire : std_logic_vector(1 downto 0); 
    signal instr_va_wire     : std_logic_vector(1 downto 0); 
    signal instr_vb_wire     : std_logic_vector(1 downto 0); 
    signal instr_vd_wire     : std_logic_vector(1 downto 0);
    signal instr_opcode_wire : std_logic_vector(3 downto 0);

    signal hazard_wire       : std_logic;
    
    signal cu_idxi_wire : std_logic_vector(3 downto 0);
    signal cu_idxj_wire : std_logic_vector(3 downto 0);
    signal cu_idxk_wire : std_logic_vector(3 downto 0);

    signal cu_idxk_we_wire : std_logic_vector(4 downto 0);

    signal cu_const6_wire : std_logic_vector(5 downto 0);
    signal cu_const4_wire : std_logic_vector(3 downto 0);

    signal cu_we_wire          : std_logic;
    signal cu_instr_fetch_wire : std_logic;
    signal cu_const_mux_wire   : std_logic;

    signal cu_alu_op_wire : std_logic_vector(3 downto 0);

    signal pipeline_alu_reg0_wire : std_logic_vector(3 downto 0);
    signal pipeline_alu_wire : std_logic_vector(3 downto 0);
    signal pipeline_vrf_wire : std_logic_vector(4 downto 0);

    signal vrf_a_wire : std_logic_vector(3 downto 0);
    signal vrf_b_wire : std_logic_vector(3 downto 0);
    signal pipeline_alu_vrf_wire : std_logic_vector(3 downto 0);

    signal mux_alu_b_wire : std_logic_vector(3 downto 0);

    signal pipeline_vrf_a_wire : std_logic_vector(3 downto 0);
    signal pipeline_vrf_b_wire : std_logic_vector(3 downto 0);

    signal alu_out_wire : std_logic_vector(3 downto 0);
    signal flags_wire : std_logic_vector(3 downto 0);

begin

    -- Decoding Instruction
    instr_const2_wire <= curr_instr_wire(1 downto 0);
    instr_vb_wire <= curr_instr_wire(3 downto 2);
    instr_va_wire <= curr_instr_wire(5 downto 4);
    instr_vd_wire <= curr_instr_wire(7 downto 6);
    instr_opcode_wire <= curr_instr_wire(11 downto 8);

    inst_mem_inst : inst_memory port map (
        RESET_i => RESET_i,
        ADDRESS_i => pc_wire,
        DATA_o => mem_instr_wire
    );

    pipeline_instruction_inst : pipeline_instruction port map (
        INPUT_i       => mem_instr_wire, 
        CLK_i         => CLK_i,
        INSTR_FETCH_i => cu_instr_fetch_wire,
        OUTPUT_REG0_o => next_instr_wire, 
        OUTPUT_o      => curr_instr_wire
    );

    control_unit_inst : control_unit port map (
        VA_i          => instr_va_wire, 
        VB_i          => instr_vb_wire,
        VD_i          => instr_vd_wire,
        CONST2_i      => instr_const2_wire,
        OPCODE_i      => instr_opcode_wire,
        HAZARD_i      => hazard_wire,
        CLK_i         => CLK_i,
        RESET_i       => RESET_i,
        IDXI_o        => cu_idxi_wire,
        IDXJ_o        => cu_idxj_wire,
        IDXK_o        => cu_idxk_wire,
        ALU_OP_o      => cu_alu_op_wire,
        CONST6_o      => cu_const6_wire,
        CONST_MUX_o   => cu_const_mux_wire,
        INSTR_FETCH_o => cu_instr_fetch_wire,
        WE_o          => cu_we_wire
    );

    cu_const4_wire <= cu_const6_wire(3 downto 0);

    hazard_unit_inst : hazards_unit port map (
        CURR_INST_i => curr_instr_wire,
        NEXT_INST_i => next_instr_wire,
        HAZARD_o	=> hazard_wire
    );

    cu_idxk_we_wire <= cu_idxk_wire & cu_we_wire;

    pipeline_cu_vrf_inst : pipeline_cu_vrf port map (
            INPUT_i  => cu_idxk_we_wire,
            CLK_i    => CLK_i,
            OUTPUT_o => pipeline_vrf_wire
    );

    pipeline_cu_alu_inst : pipeline_cu_alu port map (
            INPUT_i       => cu_alu_op_wire,
            CLK_i         => CLK_i,
            OUTPUT_REG0_o => pipeline_alu_reg0_wire,
            OUTPUT_o      => pipeline_alu_wire
    );

    vector_register_file_inst : vector_register_file port map (
        CLK_i          => CLK_i,
        WRITE_ENABLE_i => pipeline_vrf_wire(0),
        DATA_i         => pipeline_alu_vrf_wire,
        RA_i           => cu_idxi_wire(3 downto 2),
        RB_i           => cu_idxj_wire(3 downto 2),
        RD_i           => pipeline_vrf_wire(4 downto 3),
        CA_i           => cu_idxi_wire(1 downto 0),
        CB_i           => cu_idxj_wire(1 downto 0),
        CD_i           => pipeline_vrf_wire(2 downto 1),
        READ_DATA1_o   => vrf_a_wire,
        READ_DATA2_o   => vrf_b_wire
    );

    pipeline_vrf_a_inst : reg4bits port map (
        D_i   => vrf_a_wire,
        CLK_i => CLK_i,
        Q_o   => pipeline_vrf_a_wire 
    );

    pipeline_vrf_b_inst : reg4bits port map (
        D_i   => vrf_b_wire,
        CLK_i => CLK_i,
        Q_o   => pipeline_vrf_b_wire
    );

    with cu_const_mux_wire select
        mux_alu_b_wire <= 
            cu_const4_wire      when '1',
            pipeline_vrf_b_wire when others;

    alu_inst : alu port map (
        A_i      => pipeline_vrf_a_wire,
        B_i      => mux_alu_b_wire,
        C_i      => pipeline_alu_reg0_wire(0),
        ALU_OP_i => pipeline_alu_wire,
        ALU_o    => alu_out_wire,
        C_o      => flags_wire(0), 
        N_o      => flags_wire(1), 
        OVF_o    => flags_wire(2), 
        Z_o      => flags_wire(3), 
        CLK      => CLK_i
    );

    pipeline_alu_out_inst : reg4bits port map (
        D_i   => alu_out_wire,
        CLK_i => CLK_i,
        Q_o   => pipeline_alu_vrf_wire
    );

end structural;

-- vim: tabstop=4 : shiftwidth=4 : expandtab
